home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / dpmigcc5.zip / RSX / SOURCE / TERMIO.C < prev    next >
C/C++ Source or Header  |  1994-12-12  |  13KB  |  534 lines

  1. /*****************************************************************************
  2.  * FILE: termio.c                                 *
  3.  *                                         *
  4.  * DESC:                                     *
  5.  *    - ioctl() terminal functions                         *
  6.  *                                         *
  7.  * Copyright (C) 1993,1994                             *
  8.  *    Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld             *
  9.  *    email: rainer@mathematik.uni-bielefeld.de                 *
  10.  *                                         *
  11.  *****************************************************************************/
  12.  
  13. #include <ctype.h>
  14. #include "DPMI.H"
  15. #include "RMLIB.H"
  16. #include "SIGNALS.H"
  17. #include "PROCESS.H"
  18. #include "START32.H"
  19. #include "COPY32.H"
  20. #include "RSX.H"
  21. #include "EXCEP32.H"
  22. #include "TERMIO.H"
  23. #include "DOSERRNO.H"
  24. #include "PRINTF.H"
  25.  
  26. /*
  27.  *  Sourcecode based on Linux v1.1
  28.  *
  29.  *  linux/kernel/tty_io.c
  30.  *
  31.  *  Copyright (C) 1991, 1992  Linus Torvalds
  32. */
  33.  
  34. #define _O_FLAG(tty,X)    ((tty)->termios->c_oflag & (unsigned long)(X))
  35. #define _C_FLAG(tty,X)    ((tty)->termios->c_cflag & (unsigned long)(X))
  36. #define _L_FLAG(tty,X)    ((tty)->termios->c_lflag & (unsigned long)(X))
  37. #define _I_FLAG(tty,X)    ((tty)->termios->c_iflag & (unsigned long)(X))
  38.  
  39. #define L_ISIG(tty)    _L_FLAG((tty),ISIG)
  40. #define L_ICANON(tty)    _L_FLAG((tty),ICANON)
  41. #define L_XCASE(tty)    _L_FLAG((tty),XCASE)
  42. #define L_ECHO(tty)    _L_FLAG((tty),ECHO)
  43. #define L_ECHOE(tty)    _L_FLAG((tty),ECHOE)
  44. #define L_ECHOK(tty)    _L_FLAG((tty),ECHOK)
  45. #define L_ECHONL(tty)    _L_FLAG((tty),ECHONL)
  46. #define L_NOFLSH(tty)    _L_FLAG((tty),NOFLSH)
  47. #define L_IDEFAULT    _L_FLAG((tty),IDEFAULT)
  48.  
  49. #define I_IUCLC(tty)    _I_FLAG((tty),IUCLC)
  50. #define I_INLCR(tty)    _I_FLAG((tty),INLCR)
  51. #define I_ICRNL(tty)    _I_FLAG((tty),ICRNL)
  52. #define I_IGNCR(tty)    _I_FLAG((tty),IGNCR)
  53. #define I_IXON(tty)    _I_FLAG((tty),IXON)
  54. #define I_IXANY(tty)    _I_FLAG((tty),IXANY)
  55. #define I_ISTRIP(tty)    _I_FLAG((tty),ISTRIP)
  56. #define I_IDELETE(tty)    _I_FLAG((tty),IDELETE)
  57.  
  58. #define INTR_CHAR(tty)    ((tty)->termios->c_cc[VINTR])
  59. #define QUIT_CHAR(tty)    ((tty)->termios->c_cc[VQUIT])
  60. #define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
  61. #define KILL_CHAR(tty)    ((tty)->termios->c_cc[VKILL])
  62. #define EOF_CHAR(tty)    ((tty)->termios->c_cc[VEOF])
  63. #define EOL_CHAR(tty)    ((tty)->termios->c_cc[VEOL])
  64. #define __DISABLED_CHAR '\0'
  65.  
  66. #define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1))
  67. #define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1))
  68. #define EMPTY(a) ((a)->head == (a)->tail)
  69. #define LEFT(a) (((a)->tail-(a)->head-1)&(TTY_BUF_SIZE-1))
  70. #define LAST(a) ((a)->buf[(TTY_BUF_SIZE-1)&((a)->head-1)])
  71. #define FULL(a) (!LEFT(a))
  72. #define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1))
  73.  
  74. #define TTY_BUF_SIZE  128
  75. struct tty_queue {
  76.     int head;
  77.     int tail;
  78.     char buf[TTY_BUF_SIZE];
  79. };
  80.  
  81. struct tty_struct {
  82.     struct termio *termios;
  83.     int canon_data;
  84.     int canon_head;
  85.     unsigned int erasing:1;
  86.     unsigned int lnext:1;
  87.     unsigned long secondary_flags[TTY_BUF_SIZE / (sizeof(long))];
  88.     struct tty_queue secondary;
  89. };
  90.  
  91. struct termio __termios =
  92. {
  93.     BRKINT | ICRNL | IXON | IXANY,            /* iflag */
  94.     0,                            /* oflag */
  95.     B9600 | CS8 | CREAD | HUPCL,            /* cflag */
  96.     ISIG | ICANON | ECHO | ECHOE | ECHOK | IDEFAULT,    /* lflag */
  97.     0,                            /* line  */
  98.     { 003, 034, 010, 025, 004, 000, 006, 001 }        /* c_cc  */
  99.     /* INTR, QUIT,ERASE, KILL, EOF , EOL , VMIN, VTIME */
  100.     /* C-C , C-\ , C-H , C-U , C-D , EOL , VMIN, VTIME */
  101. };
  102.  
  103. struct tty_struct __tty =
  104. {
  105.     &__termios,
  106.     0,
  107.     0,
  108.     0,
  109.     0,
  110.     0,
  111.     0
  112. };
  113.  
  114. static char control_c;
  115. static unsigned long timeout;
  116.  
  117. /* flush keyboard buffer */
  118. static void keyboard_flush(void)
  119. {
  120.     while (rm_bios_read_keybrd(kready))
  121.     rm_bios_read_keybrd(kread);
  122. }
  123.  
  124. /* read a key ; extended = 0,next call scan-code */
  125. static int keyboard_read()
  126. {
  127.     static int next_key = 0;
  128.     int key, scan, ascii;
  129.  
  130.     if (next_key) {
  131.     ascii = next_key;
  132.     next_key = 0;
  133.     } else {
  134.     if (!rm_bios_read_keybrd(kready)) {
  135.         if (timeout)
  136.         if (timeout <= time_tic)
  137.             timeout = 0;
  138.         return -1;
  139.     }
  140.     key = rm_bios_read_keybrd(kread);
  141.     ascii = key & 0xff;
  142.     scan = key >> 8;
  143.  
  144.     if (ascii == 0xE0)
  145.         ascii = 0;
  146.  
  147.     if (ascii == 0)
  148.         next_key = scan;
  149.     }
  150.  
  151.     return ascii;
  152. }
  153.  
  154. int set_bit(int nr, void *vaddr)
  155. {
  156.     long mask;
  157.     int retval;
  158.     unsigned long *addr = vaddr;
  159.  
  160.     addr += nr >> 5;
  161.     mask = 1L << (nr & 0x1f);
  162.     retval = (mask & *addr) != 0;
  163.     *addr |= mask;
  164.     return retval;
  165. }
  166.  
  167. int clear_bit(int nr, void *vaddr)
  168. {
  169.     long mask;
  170.     int retval;
  171.     unsigned long *addr = vaddr;
  172.  
  173.     addr += nr >> 5;
  174.     mask = 1L << (nr & 0x1f);
  175.     retval = (mask & *addr) != 0;
  176.     *addr &= ~mask;
  177.     return retval;
  178. }
  179.  
  180. static void put_tty_queue(unsigned char c, struct tty_queue * queue)
  181. {
  182.     int head = (queue->head + 1) & (TTY_BUF_SIZE - 1);
  183.  
  184.     if (head != queue->tail) {
  185.     queue->buf[queue->head] = c;
  186.     queue->head = head;
  187.     }
  188. }
  189.  
  190. static int get_tty_queue(struct tty_queue * queue)
  191. {
  192.     int result = -1;
  193.  
  194.     if (queue->tail != queue->head) {
  195.     result = queue->buf[queue->tail];
  196.     INC(queue->tail);
  197.     }
  198.     return result;
  199. }
  200.  
  201. static void flush_input(struct tty_queue * queue)
  202. {
  203.     keyboard_flush();
  204.     queue->head = queue->tail;
  205. }
  206.  
  207. #define TTY_READ_FLUSH(tty) copy_to_cooked(tty)
  208.  
  209. static char next_line[2] = "\r\n";
  210. int output;
  211.  
  212. static int opost(unsigned char c, struct tty_struct * tty)
  213. {
  214.     if ((c == 10) && (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty))))
  215.     rm_write(output, next_line, sizeof(next_line));
  216.     else if (L_ECHO(tty))
  217.     rm_write(output, &c, 1);
  218.     return 1;
  219. }
  220.  
  221. static void echo_char(unsigned char c, struct tty_struct * tty)
  222. {
  223.     if (iscntrl(c) && c != '\t') {
  224.     opost('^', tty);
  225.     opost((unsigned char)(c ^ 0100), tty);
  226.     } else
  227.     opost((unsigned char) c, tty);
  228. }
  229.  
  230. static void eraser(unsigned char c, struct tty_struct * tty)
  231. {
  232.     enum {
  233.     ERASE, WERASE, KILL
  234.     } kill_type;
  235.     int seen_alnums;
  236.  
  237.     if (tty->secondary.head == tty->canon_head) {
  238.     /* opost('\a', tty); *//* what do you think? */
  239.     return;
  240.     }
  241.     if (c == ERASE_CHAR(tty))
  242.     kill_type = ERASE;
  243.     else {
  244.     if (!L_ECHO(tty)) {
  245.         tty->secondary.head = tty->canon_head;
  246.         return;
  247.     }
  248.     if (!L_ECHOK(tty)) {
  249.         tty->secondary.head = tty->canon_head;
  250.         if (tty->erasing) {
  251.         opost('/', tty);
  252.         tty->erasing = 0;
  253.         }
  254.         echo_char(KILL_CHAR(tty), tty);
  255.         /* Add a newline if ECHOK is on */
  256.         if (L_ECHOK(tty))
  257.         opost('\n', tty);
  258.         return;
  259.     }
  260.     kill_type = KILL;
  261.     }
  262.  
  263.     seen_alnums = 0;
  264.     while (tty->secondary.head != tty->canon_head) {
  265.     c = LAST(&tty->secondary);
  266.     DEC(tty->secondary.head);
  267.     if (L_ECHO(tty)) {
  268.         if (!L_ECHOE(tty)) {
  269.         echo_char(ERASE_CHAR(tty), tty);
  270.         }
  271.     }
  272.     if (kill_type == ERASE)
  273.         break;
  274.     }
  275.     if (tty->erasing && tty->secondary.head == tty->canon_head) {
  276.     opost('/', tty);
  277.     tty->erasing = 0;
  278.     }
  279. }
  280.  
  281. static void copy_to_cooked(struct tty_struct * tty)
  282. {
  283.     char c;
  284.  
  285.     for (;;) {
  286.     if (! LEFT(&tty->secondary))
  287.         break;
  288.  
  289.     c = (char) keyboard_read();
  290.     if (c < 0)
  291.         break;
  292.  
  293.     if (I_ISTRIP(tty))
  294.         c &= 0x7f;
  295.  
  296.     if (!tty->lnext) {
  297.         if (c == '\r') {
  298.         if (I_IGNCR(tty))
  299.             continue;
  300.         if (I_ICRNL(tty))
  301.             c = '\n';
  302.         } else if (c == '\n' && I_INLCR(tty))
  303.         c = '\r';
  304.     }
  305.     if (I_IUCLC(tty))
  306.         c = (char) tolower(c);
  307.     if (I_IDELETE(tty) && c == 8)
  308.         c = 127;
  309.  
  310.     if (c == __DISABLED_CHAR)
  311.         tty->lnext = 1;
  312.     if (L_ICANON(tty) && !tty->lnext) {
  313.         if ((unsigned char)c == ERASE_CHAR(tty) ||
  314.          (unsigned char)c == KILL_CHAR(tty)) {
  315.         eraser(c, tty);
  316.         continue;
  317.         }
  318.     }
  319.  
  320.     if (L_ISIG(tty) && !tty->lnext) {
  321.         if ((unsigned char)c == INTR_CHAR(tty)) {
  322.         control_c = 1;
  323.         send_signal(npz, SIGINT);
  324.         flush_input(&tty->secondary);
  325.         return;
  326.         }
  327.         if ((unsigned char) c == QUIT_CHAR(tty)) {
  328.         control_c = 1;
  329.         send_signal(npz, SIGQUIT);
  330.         flush_input(&tty->secondary);
  331.         return;
  332.         }
  333.     }
  334.     if (tty->erasing) {
  335.         opost('/', tty);
  336.         tty->erasing = 0;
  337.     }
  338.     if (c == '\n' && !tty->lnext) {
  339.         if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty)))
  340.         opost('\n', tty);
  341.     } else if (L_ECHO(tty)) {
  342.         /* Don't echo the EOF char in canonical mode.  Sun
  343.            handles this differently by echoing the char and
  344.            then backspacing, but that's a hack. */
  345.         if ((unsigned char) c != EOF_CHAR(tty) || !L_ICANON(tty) ||
  346.         tty->lnext) {
  347.         echo_char(c, tty);
  348.         }
  349.     }
  350.     if (c == '\377' && (c != (char)EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext))
  351.         put_tty_queue(c, &tty->secondary);
  352.  
  353.     if (L_ICANON(tty) && !tty->lnext &&
  354.         (c == '\n' || c == (char)EOF_CHAR(tty) ||
  355.         c == (char)EOL_CHAR(tty) )) {
  356.         if (c == (char)EOF_CHAR(tty))
  357.         c = __DISABLED_CHAR;
  358.         set_bit(tty->secondary.head, &tty->secondary_flags);
  359.         put_tty_queue(c, &tty->secondary);
  360.         tty->canon_head = tty->secondary.head;
  361.         tty->canon_data++;
  362.     } else
  363.         put_tty_queue(c, &tty->secondary);
  364.     tty->lnext = 0;
  365.     }
  366. }
  367.  
  368. static int input_available_p(struct tty_struct * tty)
  369. {
  370.     /* Avoid calling TTY_READ_FLUSH unnecessarily. */
  371.     if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
  372.     return 1;
  373.  
  374.     /* Shuffle any pending data down the queues. */
  375.     TTY_READ_FLUSH(tty);
  376.  
  377.     if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
  378.     return 1;
  379.     return 0;
  380. }
  381.  
  382. static int read_chan(struct tty_struct * tty, WORD ds, long buf, int nr)
  383. {
  384.     int c;
  385.     long b = buf;
  386.     int minimum, time;
  387.     int retval = 0;
  388.  
  389.     control_c = 0;
  390.  
  391.     if (L_ICANON(tty)) {
  392.     minimum = time = 0;
  393.     timeout = (unsigned long) -1;
  394.     } else {
  395.     time = tty->termios->c_cc[VTIME] * 10;
  396.     minimum = tty->termios->c_cc[VMIN];
  397.     if (minimum)
  398.         timeout = 0xffffffff;
  399.     else {
  400.         if (time)
  401.         timeout = (unsigned long) time / 55L + time_tic;
  402.         else
  403.         timeout = 0;
  404.         time = 0;
  405.         minimum = 1;
  406.     }
  407.     }
  408.  
  409.     for (;;) {
  410.     if (!input_available_p(tty)) {
  411.         if (!timeout)
  412.         break;
  413.         if (npz->filp[0]->f_flags & FCNTL_NDELAY) {
  414.         retval = -EMX_EAGAIN;
  415.         break;
  416.         }
  417.         continue;
  418.     }
  419.     for (;;) {
  420.         int eol;
  421.  
  422.         if (EMPTY(&tty->secondary))
  423.         break;
  424.  
  425.         eol = clear_bit(tty->secondary.tail, &tty->secondary_flags);
  426.         c = tty->secondary.buf[tty->secondary.tail];
  427.  
  428.         if (!nr) {
  429.         /* Gobble up an immediately following EOF if
  430.            there is no more room in buf (this can
  431.            happen if the user "pushes" some characters
  432.            using ^D).  This prevents the next read()
  433.            from falsely returning EOF. */
  434.         if (eol) {
  435.             if (c == __DISABLED_CHAR) {
  436.             tty->canon_data--;
  437.             INC(tty->secondary.tail);
  438.             } else {
  439.             set_bit(tty->secondary.tail,
  440.                 &tty->secondary_flags);
  441.             }
  442.         }
  443.         break;
  444.         }
  445.         INC(tty->secondary.tail);
  446.         if (eol) {
  447.         if (--tty->canon_data < 0) {
  448.             printf("read_chan: canon_data < 0!\n");
  449.             tty->canon_data = 0;
  450.         }
  451.         if (c == __DISABLED_CHAR)
  452.             break;
  453.         put_user_byte(ds, b, (char)c);
  454.         b++;
  455.         nr--;
  456.         break;
  457.         }
  458.         put_user_byte(ds, b++, (char)c);
  459.         nr--;
  460.     }
  461.     if ((int) (long) (b - buf >= minimum) || !nr)
  462.         break;
  463.     if (time)
  464.         timeout = time + time_tic;
  465.     }
  466.     timeout = 0;
  467.     return (int) ((b - buf) ? b - buf : retval);
  468. }
  469.  
  470. int termio_read(unsigned ds, unsigned long buf, int count)
  471. {
  472.     struct tty_struct *tty = &__tty;
  473.     output = npz->filp[1]->f_doshandle;
  474.  
  475.     if (!tty)
  476.     return -EMX_EIO;
  477.  
  478.     return read_chan(tty, ds, buf, count);
  479. }
  480.  
  481.  
  482. static DWORD do_fionread()
  483. {
  484.     struct tty_struct *tty = &__tty;
  485.     TTY_READ_FLUSH(tty);
  486.     return (DWORD) (CHARS(&tty->secondary));
  487. }
  488.  
  489. int kbd_ioctl(unsigned cmd, unsigned long termio_arg)
  490. {
  491.     struct tty_struct *tty = &__tty;
  492.  
  493.     switch (cmd) {
  494.     case TCGETA:
  495.     if (verify_illegal(npz, termio_arg, sizeof(struct termio)))
  496.         return -EMX_EINVAL;
  497.     cpy16_32(npz->data32sel, termio_arg,
  498.          tty->termios, sizeof(struct termio));
  499.     return 0;
  500.  
  501.     case TCSETAF:
  502.     flush_input(&tty->secondary);
  503.     /* fall through */
  504.     case TCSETAW:
  505.     case TCSETA:
  506.     if (verify_illegal(npz, termio_arg, sizeof(struct termio)))
  507.         return -EMX_EINVAL;
  508.     cpy32_16(npz->data32sel, termio_arg,
  509.          tty->termios, sizeof(struct termio));
  510.     flush_input(&tty->secondary);
  511.     /*if (!L_IDEFAULT)  */
  512.         npz->p_flags |= PF_TERMIO;     /* enable termio */
  513.     /*
  514.     else
  515.         npz->p_flags &= ~PF_TERMIO;
  516.     */
  517.     return 0;
  518.  
  519.     case TCFLSH:
  520.     /* if (termio_arg == 0) */
  521.     flush_input(&tty->secondary);
  522.     return 0;
  523.  
  524.     case FIONREAD:
  525.     if (verify_illegal(npz, termio_arg, sizeof(long)))
  526.         return -EMX_EINVAL;
  527.     store32(npz->data32sel, termio_arg, do_fionread());
  528.     return 0;
  529.  
  530.     default:
  531.     return -EMX_EINVAL;
  532.     }
  533. }
  534.